/**
 * form表单封装
 * @Author: linzy
 * @Date: 2022-05-12
 * 目标：
 *  1.通过json传递进来实现
 *  2.组件都可以配置
 *  3.使用方式还是跟原来一样，传参formProps forItemProps 等 抽取使用的放在外层
 *  4.表单验证题可以滚动第一个验证不过的地方
 *  5.row col默认时支持响应式
 *  6.有些需要注意的传参 跟antd这边有些许不同
 *    innerColProps 是内层的Col组件的ColProps 是为了解决wrapperCol布局问题
 *    最外层可以传递span，表示Col组件占据的格数
 *    upload 单个图片 需要返回 width height尺寸 需要传returnSize: true即可
 * @description form表单项列表封装
 * @function useFormItems
 * @param {object} rowProps - Row组件传参对象
 * @param {formItem[]} formItems - 表单项数组
 * @param {object} form - 表单form对象
 * @param {boolean} disabled - 是否禁用
 * @param {object} formItemProps - 表单项props外置
 * @param {number} span - Col组件span值
 * @property {string} label - 表单标题
 * @property {string} type - 表单类型 增加了DateMinute、DateTime、Video、Editor、NumberRange组件组件 <br />
 * type=upload,传入minCount、maxCount，label标题会默认添加最少上传、最多上传xxx个文件 <br />
 * type=Search,外置onSearch方法，enterButton默认为查询 <br />
 * type=Select,增加optionRender
 * @property {string} name - 表单字段
 * @property {boolean} required - 表单是否必填
 * @property {string} placeholder - 表单占位符 输入型的会默认添加请输入，其他会默认添加请选择 <br />
 * type=range,placeholder会默认添加开始时间、结束时间后缀 <br />
 * type=NumberRange,placeholder会默认添加下限、上限后缀 <br />
 * type=textarea,mode=shortMessage时,placeholder会默认添加请输入短信文案，58字以内。内容将以【东家App】+ 内容xxx + '空格' + 拒收请回复R 推送 <br />
 * type=input、textarea,maxLength !== undefined 时 placeholder会默认添加限制xxx个字符 <br />
 * @property {function} onChange - 表单change回调 会添加form对象 onChange(val, form)
 * @property {any} initialValue - 表单初始值
 * @property {array} rules - 表单必填项规则
 * @property {object} formItemProps - 表单传参对象
 * @property {number} span - 表单Col组件span值
 * @property {number} innerSpan - 表单Col组件内部span，解决单行时表单项的长度问题
 * @property {object} fieldProps - 表单项getFieldDecorator传参对象
 * @property {object} labelCol - 表单label 标签布局
 * @property {object} wrapperCol - 输入控件设置布局样式布局
 * @property {object} colProps - 表单Col组件传参
 * @property {object} innerColProps - 表单项内部Col组件传参对象
 * @property {number} maxLength - 表单字符长度，textarea组件默认为255
 * @property {array} options - 表单项options数组
 * @property {boolean} allowClear - 表单是否允许清除图标
 * @property {object} props - 表单项传参对象
 * @property {function} formItemRender - formItem组件render formItemRender(item, useFormItemsProps, index)
 * @property {function} fieldRender - getFieldDecorator函数render fieldRender(item, useFormItemsProps, index)
 * @property {function} render - 表单组件render render(item, useFormItemsProps, index)
 * @property {function} beforeRender - 表单组件左侧render beforeRender(item, useFormItemsProps, index)
 * @property {function} afterRender - 表单组件右侧render afterRender(item, useFormItemsProps, index)
 * @property {string|function} disabledDate - Date组件增加disabledDate 可以传 ‘before' 表示禁止之前的时间 'after' 表示禁止之后的时间，并针对该选项进行了rules的设置
 * @property {boolean|function} show - 是否显示该表单项 show (form) {}
 * @property {boolean} endOf=false - 在type为week|month|year时 传入endOf可以拿取日期结束时间戳
 * @property {boolean} exclude=false - 默认false 为true时 则会在transformValue中排除 不会传给接口
 * @property {boolean} encode=undefined - 默认undefined 为true时 会对url的search部分进行encode处理
 * @property {object} filedNames - 字段名
 * type=video时 默认值{cover: 'videoCoverPic',duration:'videoCoverDuration,url:'videoCoverUrl'} 其中 url => videoCoverUrl 作为formItem的name名 <br />
 * type=Cascader时 默认值{label: "name",value: "id",children: "children"} <br />
 * <caption>formItem - 表单项对象</caption>
 */
import React from "react";
import {
  Select,
  RangePicker,
  Upload,
  NumberRange,
  TextArea,
  Video,
  Editor,
  InputNumber
} from "@/hooks/components";
import { typeOf } from "@/hooks/tools";
import moment from "moment";
import useFormTypes from "./useFormTypes";
import { DJMulCropUpload } from "@/components";
import {
  Form,
  Row,
  Col,
  AutoComplete,
  Checkbox,
  Cascader,
  DatePicker,
  Input,
  Rate,
  Radio,
  Switch,
  Slider,
  TreeSelect,
  Transfer,
  TimePicker
} from "antd";
import { setOutAttrs, setDefaultAttrs, setAlias } from "@/hooks/tools";
import styles from "./useFormItems.less";
import UploadFile from "@/hooks/components/UploadFile";
const normFile = e => {
  if (Array.isArray(e)) {
    return e;
  }
  return e && e.fileList;
};

export default useFormItemsProps => {
  // 外层的props还有span 控制全局的span
  const {
    rowProps = {},
    formItems = [],
    form,
    disabled
    // formItemProps = {},
    // span, // 在下方通过 useFormItemsProps.span加入
  } = useFormItemsProps;
  setDefaultAttrs(rowProps, {
    gutter: 10
  });
  const { getFieldDecorator } = form;
  // 封装一些常用的表单组合 比如 跳转协议
  useFormTypes(formItems, form);
  // 处理show 做display处理 否则会出现显示不出来的问题；
  formItems.forEach(item => {
    if (item.show !== undefined) {
      // show 传入函数 判断是否显示
      var isShow = true;
      if (typeOf(item.show) === "function") {
        isShow = item.show(form, item);
      } else if (item.show !== undefined) {
        isShow = item.show;
      }
      if (isShow === false) {
        if (!item.need) {
          item.exclude = true;
        }
        item.colProps = {
          ...item.colProps,
          style: {
            display: "none"
          }
        };
      } else {
        item.exclude = false;
        item.colProps = {
          ...item.colProps,
          style: {
            display: "block"
          }
        };
      }
    }
  });
  return (
    <Row {...rowProps}>
      {formItems.map((item, index) => {
        const {
          label,
          type,
          name,
          required,
          placeholder,
          onChange,
          initialValue,
          rules,
          formItemProps = {},
          span,
          innerSpan = 24, // innerColProps 是为了解决wrapperCol布局问题
          fieldProps = {},
          labelCol,
          wrapperCol,
          colProps = {},
          innerColProps = {}, // innerColProps 是为了解决wrapperCol布局问题
          onSearch, // input.search组件需要
          multiple, // 下拉框的 多选
          fieldNames, // 级联选择器的 字段映射
          optionRender, // select选择器的 option render
          showSearch, // select选择器的 是否带搜索
          filterOption, // select选择器的 搜索filter函数
          mode, // select选择器的 mode
          selectMode, // 因mode冲突 所以加一个 selectMode 传值ids 实现验证数组ids传参
          min, // inputNumber 最小值
          max, // inputNumber 最大值
          maxLength,
          presets, // range 日期预设
          ranges, // range 组件的预设
          options,
          map,
          allowClear,
          disabledDate,
          crop,
          disabledDateType, // Date组件disabledDate类型 有before、after
          props = {}
        } = item;
        // 处理 colProps
        // { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4 }
        setDefaultAttrs(colProps, {
          span: colProps.span ?? span ?? useFormItemsProps.span ?? 24
        });
        setDefaultAttrs(innerColProps, { span: innerSpan });
        // 处理 fieldProps
        setOutAttrs(fieldProps, { rules, initialValue, required });
        if (typeof fieldProps.required === "function") {
          fieldProps.required = fieldProps.required(form);
        }
        // 处理formItemProps常用放在外层的
        setOutAttrs(formItemProps, {
          ...useFormItemsProps.formItemProps,
          type,
          label,
          required,
          wrapperCol,
          labelCol
        });
        // 处理props 公共属性
        setOutAttrs(props, {
          presets,
          ranges,
          placeholder,
          maxLength,
          options,
          map,
          allowClear,
          disabledDate,
          mode,
          crop,
          multiple,
          fieldNames
        });
        setDefaultAttrs(props, {
          allowClear: true,
          disabled: disabled || props.disabled || item.disabled || false,
          crop: false
        });
        setDefaultAttrs(fieldProps, {
          valuePropName: /(Switch|Checkbox)$/i.test(type)
            ? "checked"
            : /Upload/i.test(type) && props.crop !== true
            ? "fileList"
            : /Video/i.test(type)
            ? "fileList"
            : "value"
        });
        if (fieldProps.valuePropName === "fileList") {
          fieldProps.getValueFromEvent = normFile;
        }
        if (/^Range/i.test(type)) {
          if (
            typeof props.placeholder === "string" &&
            /\,/.test(props.placeholder)
          ) {
            props.placeholder = props.placeholder.split(",");
          } else if (typeof props.placeholder === "string") {
            props.placeholder = [
              props.placeholder + "开始时间",
              props.placeholder + "结束时间"
            ];
          } else if (!props.placeholder) {
            props.placeholder = ["开始时间", "结束时间"];
          }
        }
        if (/^NumberRange/i.test(type)) {
          if (
            typeof props.placeholder === "string" &&
            /\,/.test(props.placeholder)
          ) {
            props.placeholder = props.placeholder.split(",");
          } else if (typeof props.placeholder === "string") {
            props.placeholder = [
              props.placeholder + "下限",
              props.placeholder + "上限"
            ];
          } else if (!props.placeholder) {
            props.placeholder = ["下限", "上限"];
          }
        }
        if (type === "textarea") {
          if (props.mode === "shortMessage") {
            setDefaultAttrs(props, {
              placeholder:
                "请输入短信文案，58字以内。内容将以【东家App】+ 内容xxx + '空格' + 拒收请回复R 推送",
              showCount: true
            });
          }
        }
        if (/^Select$/i.test(type)) {
          setOutAttrs(props, { optionRender, mode, showSearch, filterOption });
          if (selectMode === "ids") {
            setDefaultAttrs(props, {
              mode: "tags",
              tokenSeparators: [","],
              notFoundContent: null,
              placeholder: "输入ID，多个之间用英文逗号”,“隔开"
            });
            setDefaultAttrs(fieldProps, {
              rules: [
                {
                  validator(rule, value, cb) {
                    if (value) {
                      let str = value.join("");
                      if (str && /\D/g.test(str)) {
                        cb("请填写正确的id");
                      } else {
                        cb();
                      }
                    } else {
                      cb();
                    }
                  }
                }
              ]
            });
          }
        }
        setDefaultAttrs(props, {
          placeholder: /AutoComplete|Input|TextArea/i.test(type)
            ? "请输入"
            : "请选择"
        });
        if (type === "input") {
          if (props.maxLength && !/限制\d+个字符/g.test(props.placeholder)) {
            setDefaultAttrs(props, {});
            props.placeholder += "，" + `限制${props.maxLength}个字符`;
          }
        }
        if (type === "textarea") {
          if (
            props.maxLength &&
            props.mode !== "shortMessage" &&
            !props.showCount &&
            !/限制\d+个字符/g.test(props.placeholder)
          ) {
            props.placeholder += "，" + `限制${props.maxLength}个字符`;
          }
        }
        if (typeOf(onChange) === "function") {
          props.onChange = function (val) {
            onChange(val, form);
          };
        }
        if (/DateMinute$/i.test(type)) {
          props.format = props.format ?? "YYYY-MM-DD HH:mm";
          props.showTime = props.showTime ?? { format: "HH:mm" };
        }
        if (/DateTime$/i.test(type)) {
          props.format = props.format ?? "YYYY-MM-DD HH:mm:ss";
          props.showTime = props.showTime ?? { format: "HH:mm:ss" };
        }
        if (/^(Date|Range)/i.test(type)) {
          if (disabledDateType === "before" || disabledDateType === "after") {
            let validator = (rule, value, cb) => {
              if (typeOf(value) === "array") {
                if (disabledDateType === "before") {
                  value = value[0];
                } else if (disabledDateType === "after") {
                  value = value[1];
                }
              }
              if (value && props.disabled !== true) {
                if (
                  disabledDateType === "before" &&
                  value.valueOf() <= moment().valueOf()
                ) {
                  cb((label || "开始时间") + "要大于当前时间");
                } else if (
                  disabledDateType === "after" &&
                  value.valueOf() >= moment().valueOf()
                ) {
                  cb((label || "开始时间") + "要大于当前时间");
                } else {
                  cb();
                }
              } else if (fieldProps.required) {
                cb();
              } else {
                cb();
              }
            };
            if (fieldProps.rules) {
              if (!_.last(fieldProps.rules).validator) {
                fieldProps.rules.push({ validator });
              }
            } else {
              fieldProps.rules = [{ validator }];
            }
          }
          if (disabledDateType === "before") {
            props.disabledDate = currentDate => {
              return (
                moment(currentDate).valueOf() <=
                moment().subtract("day", 1).valueOf()
              );
            };
          } else if (disabledDateType === "after") {
            props.disabledDate = currentDate => {
              return moment(currentDate).valueOf() >= moment().valueOf();
            };
          }
        }
        if (/Upload$/i.test(type)) {
          // 设置别名
          if (props.crop === true) {
            setAlias(props, { maxLen: "maxCount", aspectRatio: "ratio" });
            // upload 传fitContent: true 实现图片自适应显示
            formItemProps.className = formItemProps.className
              ? formItemProps.className + " " + styles.fitContentUpload
              : styles.fitContentUpload;
          }
          setOutAttrs(props, {
            count: item.count,
            maxSize: item.maxSize,
            width: item.width,
            height: item.height,
            multiple: item.multiple,
            minCount: item.minCount,
            maxCount: item.maxCount,
            ratio: item.ratio,
            ratioLimits: item.ratioLimits
          });
          props.crop === true && (fieldProps.initialValue = []);
          if (props.minCount) {
            formItemProps.label = (
              <>
                {formItemProps.label}
                <small> 至少上传{props.minCount}个文件</small>
              </>
            );
            fieldProps.rules = [
              ...(fieldProps.rules || []),
              {
                required: true,
                validator: (rule, value, cb) => {
                  if (value.length < props.minCount) {
                    cb(`至少上传${props.minCount}个文件`);
                  } else {
                    cb();
                  }
                }
              }
            ];
          }
          if (props.maxCount) {
            formItemProps.label = (
              <>
                {formItemProps.label}
                <small> 最多上传{props.maxCount}个文件</small>
              </>
            );
          }
        }
        if (/Search$/i.test(type)) {
          setOutAttrs(props, { onSearch });
          setDefaultAttrs(props, { enterButton: "查询" });
          props.enterButton = props.enterButton ?? "查询";
        }
        if (/Cascader$/i.test(type)) {
          setDefaultAttrs(props, {
            fieldNames: {
              label: "name",
              value: "id",
              children: "children"
            }
          });
        }

        if (/^input$/i.test(type)) {
          if (mode) {
            switch (mode) {
              case "tel":
                setDefaultAttrs(props, {
                  maxLength: 12
                });
                if (item.rules) {
                  var isSome = item.rules.some(
                    o => o.message === "请输入正确的手机号码"
                  );
                  !isSome &&
                    (item.rules = [
                      ...(item.rules || []),
                      {
                        validator(rule, value, cb) {
                          if (value) {
                            if (value[0] === "1" && /^1\d{10}$/.test(value)) {
                              cb();
                            } else if (
                              value[0] === "0" &&
                              /^0(\d{10}|\d{11})$/.test(value)
                            ) {
                              cb();
                            } else {
                              cb("请输入正确的联系方式");
                            }
                          } else {
                            cb();
                          }
                        },
                        message: "请输入正确的手机号码"
                      }
                    ]);
                } else {
                  item.rules = [];
                }
                break;
              default:
                break;
            }
          }
        }
        if (/^inputNumber$/i.test(type)) {
          setOutAttrs(props, { min, max, mode });
          if (mode) {
            switch (mode) {
              case "int":
                setDefaultAttrs(props, {
                  min: 0,
                  max: 999999999999,
                  precision: 0
                });
                break;
              case "weight":
                setDefaultAttrs(props, {
                  min: 0,
                  max: 999999,
                  precision: 0
                });
                break;
              case "price":
                setDefaultAttrs(props, {
                  min: 0,
                  max: 999999999999,
                  precision: 2
                });
                break;
              case "rate":
                setDefaultAttrs(props, {
                  min: 0,
                  max: 1,
                  precision: 2,
                  step: 0.1
                });
                break;
              default:
                break;
            }
          }
        }
        if (/^TextArea$/i.test(type)) {
          setDefaultAttrs(props, {
            autoSize: { minRows: 1, maxRows: Infinity },
            maxLength: 255
          });
        }
        // 单选默认选择第一项
        if (/^radio$/i.test(type)) {
          if (fieldProps.required && props.options) {
            fieldProps.initialValue =
              fieldProps.initialValue ??
              (props.map
                ? props.options[0]?.[props.map?.value]
                : props.options[0]?.value);
          }
        }
        if (
          label &&
          item.fieldRender &&
          !item.fieldRender(item, useFormItemsProps, index)
        ) {
          if (formItemProps.style) {
            formItemProps.style = { marginBottom: 0, ...formItemProps.style };
          } else {
            formItemProps.style = {
              marginBottom: 0
            };
          }
          formItemProps.colon ?? (formItemProps.colon = false);
        }
        if (fieldProps.required) {
          if (!fieldProps.rules) {
            fieldProps.rules = [
              {
                required: true,
                message:
                  (/AutoComplete|Input|TextArea|Search/i.test(type)
                    ? "请输入"
                    : "请选择") + (label ? label : "")
              }
            ];
          } else if (fieldProps.rules[0]?.required !== true) {
            fieldProps.rules.unshift({
              required: true,
              message:
                (/AutoComplete|Input|TextArea|Search/i.test(type)
                  ? "请输入"
                  : "请选择") + (label ? label : "")
            });
          }
        }
        return (
          <>
            <Col {...colProps}>
              <Col {...innerColProps}>
                {item.formItemRender ? (
                  item.formItemRender(item, useFormItemsProps, index)
                ) : (
                  <Form.Item {...formItemProps}>
                    {item.beforeRender &&
                      item.beforeRender(item, useFormItemsProps, index)}
                    {item.fieldRender
                      ? item.fieldRender(item, useFormItemsProps, index)
                      : getFieldDecorator(
                          name,
                          fieldProps
                        )(
                          item.render ? (
                            item.render(item, useFormItemsProps, index)
                          ) : /^AutoComplete$/i.test(type) ? (
                            <AutoComplete {...props} />
                          ) : /^Checkbox$/i.test(type) && !props.options ? (
                            <Checkbox {...props} />
                          ) : /^Checkbox$/i.test(type) && props.options ? (
                            <Checkbox.Group {...props} />
                          ) : /^Cascader$/i.test(type) ? (
                            <Cascader {...props} />
                          ) : /^(Date|dateMinute|datetime)$/i.test(type) ? (
                            <DatePicker {...props} />
                          ) : /^Month/i.test(type) ? (
                            <DatePicker.MonthPicker {...props} />
                          ) : /^Range/i.test(type) ? (
                            <RangePicker {...props} />
                          ) : /^Week$/i.test(type) ? (
                            <DatePicker.WeekPicker {...props} />
                          ) : /^InputNumber$/i.test(type) ? (
                            <InputNumber {...props} />
                          ) : /^Input$/i.test(type) ? (
                            <Input {...props} />
                          ) : /Search/i.test(type) ? (
                            <Input.Search {...props} />
                          ) : /^TextArea$/i.test(type) ? (
                            <TextArea {...props} />
                          ) : /^Rate$/i.test(type) ? (
                            <Rate {...props} />
                          ) : /^Radio$/i.test(type) ? (
                            <Radio.Group {...props} />
                          ) : /^Switch$/i.test(type) ? (
                            <Switch {...props} />
                          ) : /^Slider$/i.test(type) ? (
                            <Slider {...props} />
                          ) : /^Select$/i.test(type) ? (
                            <Select {...props} />
                          ) : /^Tree/i.test(type) ? (
                            <TreeSelect {...props} />
                          ) : /^Transfer$/i.test(type) ? (
                            <Transfer {...props} />
                          ) : /^Time/i.test(type) ? (
                            <TimePicker {...props} />
                          ) : /^Upload/i.test(type) && props.type === "file" ? (
                            <UploadFile {...props} />
                          ) : /^Upload/i.test(type) && props.crop !== true ? (
                            <Upload {...props} />
                          ) : /^Upload/i.test(type) && props.crop === true ? (
                            <DJMulCropUpload {...props} />
                          ) : /^NumberRange/i.test(type) ? (
                            <NumberRange {...props} />
                          ) : /^Video/i.test(type) ? (
                            <Video {...props} />
                          ) : /^Editor/i.test(type) ? (
                            <Editor {...props} />
                          ) : null
                        )}
                    {item.afterRender &&
                      item.afterRender(item, useFormItemsProps, index)}
                  </Form.Item>
                )}
              </Col>
            </Col>
          </>
        );
      })}
    </Row>
  );
};
